package 个人密码库.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

public class Encryptor {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final String SECRET_KEY = System.getProperty("user.name", "miku");

    // 加密
    public static String encrypt(String data) throws GeneralSecurityException {
        PBEKeySpec keySpec = new PBEKeySpec(SECRET_KEY.toCharArray());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
        // 16 bytes随机Salt:
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, pbeParameterSpec);
        byte[] result = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

        // 连接salt和密码
        byte[] combination = new byte[salt.length + result.length];
        System.arraycopy(salt, 0, combination, 0, salt.length);
        System.arraycopy(result, 0, combination, salt.length, result.length);

        // 注意：这里只能用Base64对二进制数据进行编码，否则会报错！
        return Base64.getEncoder().encodeToString(combination);
    }

    // 解密
    public static String decrypt(String data) throws GeneralSecurityException {
        PBEKeySpec pbeKeySpec = new PBEKeySpec(SECRET_KEY.toCharArray());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);

        byte[] row = Base64.getDecoder().decode(data);
        byte[] salt = new byte[16];
        byte[] result = new byte[row.length - salt.length];
        for (int i = 0; i < row.length; i++) {
            if (i < salt.length) {
                salt[i] = row[i];
            } else {
                result[i - salt.length] = row[i];
            }
        }

        PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, pbeParameterSpec);

        return new String(cipher.doFinal(result));
    }
}
